import type { ReactNode, FC, CSSProperties } from "react";

export interface FieldBaseType<VALUE = any, META = Record<string, any>> {
  key: string; // form 需要匹配数据，这里对应数据的中的key
  type: string;
  value?: VALUE;
  defaultValue?: VALUE;
  label?: string; // 字段 label 描述
  labelTips?: React.ReactNode; // 字段 label 后面的提示信息
  prefix?: string; //前缀元素
  suffix?: string; // 后缀文字
  note?: string; // 补充说明，对整个 field 的补充说明
  meta?: META; // meta 参数，用于继承，为每个field 增加一个灵活的配置项
  placeholder?: string;
  disabled?: boolean; // 字段是否为禁用状态
  required?: boolean; // 是否必填
  options?:
    | Array<FormViewFieldOption>
    | ((
        text?: string,
        selected?: Array<VALUE>
      ) => Promise<Array<FormViewFieldOption>>);
  // 补充校验方法，对特殊业务字段增加针对性的校验
  validate?: FormViewValidate<VALUE>; // 检查字段值，并返回 [校验是否通过，错误提示信息]
  onChange?: (v: VALUE, isValid: boolean) => void;
}

export type FormViewValidate<VALUE> = (
  value: VALUE | undefined,
  field: FieldBaseType
) => { isValid: boolean; errmsg?: string } | undefined;

export type FormViewJustifyContent =
  | "flex-start"
  | "flex-end"
  | "center"
  | "space-between"
  | "space-evenly"
  | "space-around";

export type CustomFieldComponent = FC<{
  field: FieldBaseType;
  isValid: boolean;
  showError: boolean;
  onChange: (value: any) => void;
}>;

export type SelfDefinedField<CustomField extends FieldBaseType> =
  | CustomField
  | FieldType;

export type FormProps<T> = {
  fields: Array<T>;
  validates?: ValidateFnType;
  onChange?: onChangeFnType;
};

type ValidateFnType = (data: Array<any>) => {
  isValid: boolean;
  errmsg?: string;
};

type onChangeFnType = (data: Array<any>, isValid: boolean) => void;

interface DefaultFieldBaseType extends FieldBaseType {
  type:
    | "boolean"
    | "cascader"
    | "checkbox"
    | "date_range"
    | "date"
    | "datetime_range"
    | "datetime"
    | "multi_select"
    | "number"
    | "password"
    | "radio"
    | "select"
    | "string"
    | "switch"
    | "tag"
    | "textarea"
    | "url_array"
    | "url";
}

export interface FormViewProps<T extends FieldBaseType = DefaultFieldBaseType> {
  title?: string;
  column?: 1 | 2 | 3 | number;
  showError?: boolean;
  labelWidth?: string | number;
  style?: CSSProperties;
  justify?: FormViewJustifyContent;
  className?: string;
  /**
   * form 等于 fields + validates + onChange，用来在 useFormView 中方便的表示
   * 如果设置了 form，则忽略另外3个参数
   */
  form?: FormProps<T>;
  fields?: Array<T>;
  onChange?: (
    kvData: Record<string, any>,
    isValid: boolean,
    arrData: Array<{ key: string; value: any }>
  ) => void;
}

export interface FormItemProps<FIELD extends FieldBaseType = FieldBaseType> {
  field: FIELD;
  isLast: boolean;
  index: number; // 在 form items 中的顺序编号
  isValid: boolean;
  showError: boolean;
  justify?: FormViewJustifyContent;
  labelWidth?: string | number;
  labelTips?: ReactNode;
  errmsg?: string;
  onChange: (index: number, value: any) => void;
}

type FormViewFieldOption = {
  value: string | number;
  label: string;
  children?: Array<FormViewFieldOption>;
};

interface StringField
  extends FieldBaseType<string, { min?: number; max?: number }> {
  type: "string";
}

interface NumberField
  extends FieldBaseType<number, { min?: number; max?: number }> {
  type: "number";
}

interface NumberWithUnitField
  extends FieldBaseType<
    { value?: number; unit?: string },
    { min?: number; max?: number }
  > {
  type: "number_with_unit";
}

interface BooleanField extends FieldBaseType<boolean> {
  type: "boolean";
}

interface UrlField extends FieldBaseType<string> {
  type: "url";
}

interface RatioField extends FieldBaseType<string | number> {
  type: "radio";
}

interface CheckboxField
  extends FieldBaseType<Array<string | number>, { min?: number }> {
  type: "checkbox";
}

interface PasswordField
  extends FieldBaseType<
    string,
    {
      min?: number;
      max?: number;
      needNumber?: boolean;
      needLowercase?: boolean;
      needUppercase?: boolean;
      needSpecialCharacter?: boolean;
    }
  > {
  type: "password";
}

interface DateField extends FieldBaseType<number | Date | null> {
  type: "date";
}

interface DatetimeField extends FieldBaseType<number | Date | null> {
  type: "datetime";
}

interface DateRangeField extends FieldBaseType<[number, number]> {
  type: "date_range";
}

interface DatetimeRangeField extends FieldBaseType<[number, number]> {
  type: "datetime_range";
}

interface TextareaField
  extends FieldBaseType<
    string,
    {
      // autoSize?: boolean | { minRows: number; maxRows: number };
      maxLength?: number;
      // showCount?: boolean;
    }
  > {
  type: "textarea";
}

interface TagsField extends FieldBaseType<Array<string>> {
  type: "tag";
}

interface SelectField
  extends FieldBaseType<
    string | number | null,
    {
      search: boolean;
      width?: string;
      notFoundContent?: React.ReactNode;
      allowClear?: boolean;
    }
  > {
  type: "select";
}

interface MultipleSelectField
  extends FieldBaseType<
    Array<string | number> | null,
    { search: boolean; notFoundContent?: React.ReactNode }
  > {
  type: "multi_select";
}

interface SwitchField extends FieldBaseType<boolean> {
  type: "switch";
}

interface CascaderField
  extends FieldBaseType<
    Array<string | number>,
    { allowClear?: boolean; changeOnSelect?: boolean; notFoundContent?: string }
  > {
  type: "cascader";
}

interface UrlArrayField extends FieldBaseType<Array<string>> {
  type: "url_array";
}

interface IpField
  extends FieldBaseType<string, { ipv4?: boolean; ipv6?: boolean }> {
  type: "ip";
}

/* other type
upload

// interface InlineFormField
//   extends FieldBaseType<
//     any,
//     {
//       bordered: boolean; // 是否有边线
//     }
//   > {
//   type: "inline_form";
//   form: FormViewProps;
// }

// interface InlineFormArrayField extends FieldBaseType<any> {
//   type: "inline_form_array";
//   form: FormViewProps;
// }
*/

export type FieldType =
  | BooleanField
  | CascaderField
  | CheckboxField
  | DateField
  | DateRangeField
  | DatetimeField
  | DatetimeRangeField
  | IpField
  | MultipleSelectField
  | NumberField
  | NumberWithUnitField
  | PasswordField
  | RatioField
  | SelectField
  | StringField
  | SwitchField
  | TagsField
  | TextareaField
  | UrlArrayField
  | UrlField;
// | InlineFormField
// | InlineFormArrayField;
